﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Configuration;
using System.Data;
using System.IO;
using System.Data.SQLite;
using System.Runtime.InteropServices;
using System.Drawing;
using LevelEditor.Objects.Waypoints;
using DialogsEditor;
using DialogsEditor.DAO;
using LevelEditor.Objects.Collisions;
using LevelEditor.App;

namespace LevelEditor.Dao
{
    class LevelEditorDAO
    {
        private static readonly LevelEditorDAO Instance = new LevelEditorDAO();

        private SQLiteConnection connection;


        public static LevelEditorDAO GetInstance()
         {
            return Instance;
        }

        public SQLiteConnection GetConnection()
        {
            return ConnFactory.getInstancia().GetConnLevel();
        }

        #region BD

        private void Save(string sql)
        {
            connection = GetConnection();

            SQLiteCommand cmd = new SQLiteCommand(sql, connection);
            connection.Open();
            cmd.ExecuteNonQuery();

            connection.Close();
            
        }

        private void Update(string sql)
        {
            connection = GetConnection();

            SQLiteCommand cmd = new SQLiteCommand(sql, connection);
            
            connection.Open();
            cmd.ExecuteNonQuery();

            connection.Close();
        }

        private void Delete(string sql)
        {
            connection = GetConnection();

            SQLiteCommand cmd = new SQLiteCommand(sql, connection);
            connection.Open();
            cmd.ExecuteNonQuery();

            connection.Close();
        }

        #endregion

        #region Behavior

        public bool SaveWalkBehavior(Behavior wBehavior)
        {
            bool result = false;
            string sql = "insert into behavior(nameBehavior, images, isSpriteSheet, isWalk, time) values ('" + wBehavior.Name.ToUpper() + "', 'imagesPath', bool, www, durationTime)";

            string imagesPath = CreateImagesPath(wBehavior);

            if (string.IsNullOrEmpty(imagesPath))
                return false;

            sql = sql.Replace("imagesPath", imagesPath);
            sql = sql.Replace("bool", (Convert.ToInt32(wBehavior.IsSpriteSheet())).ToString());
            sql = sql.Replace("www", Convert.ToInt32(true).ToString());
            sql = sql.Replace("durationTime", wBehavior.DurationTime.ToString());
            try
            {
                Save(sql);
                result = true;
            }
            catch (DuplicateNameException)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_EXISTS_WBEHAVIOR);
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_WBEHAVIOR_SAVE);
            }

            return result;
        }

        public bool SaveBehavior(Behavior newBehavior)
        {
            bool result = false;
            string sql = "insert into behavior(nameBehavior, images, isSpriteSheet, isWalk, time) values ('" + newBehavior.Name.ToUpper() + "', 'imagesPath', bool, walk1, durationTime)";

            string imagesPath = CreateImagesPath(newBehavior);
            
            if (string.IsNullOrEmpty(imagesPath))
                return false;

            sql = sql.Replace("imagesPath", imagesPath);
            sql = sql.Replace("bool", (Convert.ToInt32(newBehavior.IsSpriteSheet())).ToString());
            sql = sql.Replace("walk1", "0");
            sql = sql.Replace("durationTime", newBehavior.DurationTime.ToString());
            try
            {
                Save(sql);
                result = true;
            }
            catch (DuplicateNameException)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_EXISTS_BEHAVIOR);
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_BEHAVIOR_SAVE);
            }

            return result;
        }

        public string CreateImagesPath(Behavior b)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory + "\\savedBehaviors";
            string paths = "";

            try
            {
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                path += "\\" + b.Name;

                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DIRECTORY_OP);
                return "";
            }

            path += "\\";

            for (int k = 0; k < b.Images.Count; k++)
            {

                if (File.Exists(path + b.Name + k.ToString() + ".png"))
                    File.Delete(path + b.Name + k.ToString() + ".png");
                
                b.Images[k].Save(path + b.Name + k.ToString() + ".png", System.Drawing.Imaging.ImageFormat.Png);
                paths += path + b.Name + k.ToString() + ".png";

                if (b.Images.Count > 1)
                    paths += ";";
            }

            return paths;
        }

        public bool UpdateBehavior(Behavior b)
        {
            bool result = false;
            string sql = "update behavior set nameBehavior = '" + b.Name.ToUpper() + "', images = 'bImages', isSpriteSheet = bIsSpriteS, isWalk = bIsWalk, time = durationTime where id = " + b.ID;
            sql = sql.Replace("bImages", CreateImagesPath(b));
            sql = sql.Replace("bIsSpriteS", Convert.ToInt32(b.IsSpriteSheet()).ToString());
            sql = sql.Replace("bIsWalk", Convert.ToInt32(b.IsWalk).ToString());
            sql = sql.Replace("durationTime", b.DurationTime.ToString());

            try
            {
                Update(sql);
                result = true;
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_BEHAVIOR_UPDATE);
            }

            return result;
        }

        public List<Behavior> GetAllBehavior()
        {
            connection = GetConnection();
            List<Behavior> result = new List<Behavior>();
            //MySqlConnection conn = Instance.GetConnection();
            SQLiteDataReader reader = null;
            try
            {
                string sql = "select * from behavior";
                connection.Open();
                SQLiteCommand cmd = new SQLiteCommand(sql, connection);
                reader = cmd.ExecuteReader();

                while (reader.Read())
                {

                    Behavior b = new Behavior(reader.GetBoolean(4));
                    b.ID = reader.GetInt32(0);
                    b.Name = reader.GetString(1);
                    b.DurationTime = reader.GetInt32(5);
                    string imageData = reader.GetString(2);

                    if (reader.GetBoolean(3)) // is spriteSheet
                    {
                        FileStream fs = new FileStream(imageData, FileMode.Open);
                        b.Images.Add(Bitmap.FromStream(fs));
                        fs.Close();
                    }
                    else
                    {
                        string[] images = imageData.Split(new char[] { ';' });
                        for (int k = 0; k < images.Length - 1; k++)
                        {
                            FileStream fs = new FileStream(images[k], FileMode.Open);
                            b.Images.Add(Bitmap.FromStream(fs));
                            fs.Close();
                        }
                    }

                    result.Add(b);
                }
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_ALL_BEHAVIOR);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                connection.Close();
            }

            return result;
        }

        public List<Behavior> GetAllWalkBehavior()
        {
            string query = "SELECT * FROM behavior WHERE isWalk = 1";
            List<Behavior> walkBehaviors = new List<Behavior>();

            connection = GetConnection();
            SQLiteDataReader sqlReader = null;

            try
            {
                connection.Open();
                SQLiteCommand sLiteCommand = new SQLiteCommand(query, connection);
                sqlReader = sLiteCommand.ExecuteReader();

                while (sqlReader.Read())
                {
                    Behavior wBehavior = new Behavior(true);
                    wBehavior.ID = sqlReader.GetInt32(0);
                    wBehavior.Name = sqlReader.GetString(1);
                    wBehavior.DurationTime = sqlReader.GetInt32(5);
                    string imageData = sqlReader.GetString(2);
                    if (sqlReader.GetBoolean(3)) // is spriteSheet
                    {
                        FileStream fs = new FileStream(imageData, FileMode.Open);
                        wBehavior.Images.Add(Bitmap.FromStream(fs));
                        fs.Close();
                    }
                    else
                    {
                        string[] images = imageData.Split(new char[]{';'});
                        for (int k = 0; k < images.Length-1; k++)
                        {
                            FileStream fs = new FileStream(images[k], FileMode.Open);
                            wBehavior.Images.Add(Bitmap.FromStream(fs));
                            fs.Close();
                        }
                    }

                    walkBehaviors.Add(wBehavior);
                }

                sqlReader.Close();
                connection.Close();
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_ALL_WBEHAVIOR);
            }

            return walkBehaviors;
        }

        public Behavior getBehavior(string behaviorName)
        {
            string query = "SELECT * FROM behavior WHERE nameBehavior = 'behaviorName'";
            query = query.Replace("behaviorName", behaviorName);

            connection = GetConnection();
            SQLiteDataReader sqlReader = null;
            Behavior b = null;
            try
            {
                connection.Open();
                SQLiteCommand sLiteCommand = new SQLiteCommand(query, connection);
                sqlReader = sLiteCommand.ExecuteReader();

                while (sqlReader.Read())
                {
                    b = new Behavior(sqlReader.GetBoolean(4));
                    b.Name = sqlReader.GetString(1);
                    b.ID = sqlReader.GetInt32(0);
                    b.DurationTime = sqlReader.GetInt32(5);
                    string imageData = sqlReader.GetString(2);
                    if (sqlReader.GetBoolean(3)) // is spriteSheet
                    {
                        FileStream fs = new FileStream(imageData, FileMode.Open);
                        b.Images.Add(Bitmap.FromStream(fs));
                        fs.Close();
                    }
                    else
                    {
                        string[] images = imageData.Split(new char[] { ';' });
                        for (int k = 0; k < images.Length - 1; k++)
                        {
                            FileStream fs = new FileStream(images[k], FileMode.Open);
                            b.Images.Add(Bitmap.FromStream(fs));
                            fs.Close();
                        }
                    }
                }

                sqlReader.Close();
                connection.Close();
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_BEHAVIOR);
            }

            return b;
        }

        public Behavior getBehavior(int id)
        {
            string query = "SELECT * FROM behavior WHERE id = idBehavior";
            query = query.Replace("idBehavior", id.ToString());

            connection = GetConnection();
            SQLiteDataReader sqlReader = null;
            Behavior b = null;
            try
            {
                connection.Open();
                SQLiteCommand sLiteCommand = new SQLiteCommand(query, connection);
                sqlReader = sLiteCommand.ExecuteReader();

                while (sqlReader.Read())
                {
                    b = new Behavior(sqlReader.GetBoolean(4));
                    b.Name = sqlReader.GetString(1);
                    b.ID = sqlReader.GetInt32(0);
                    b.DurationTime = sqlReader.GetInt32(5);
                    string imageData = sqlReader.GetString(2);
                    if (sqlReader.GetBoolean(3)) // is spriteSheet
                    {
                        FileStream fs = new FileStream(imageData, FileMode.Open);
                        b.Images.Add(Bitmap.FromStream(fs));
                        fs.Close();
                    }
                    else
                    {
                        string[] images = imageData.Split(new char[] { ';' });
                        for (int k = 0; k < images.Length - 1; k++)
                        {
                            FileStream fs = new FileStream(images[k], FileMode.Open);
                            b.Images.Add(Bitmap.FromStream(fs));
                            fs.Close();
                        }
                    }
                }

                sqlReader.Close();
                connection.Close();
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_BEHAVIOR);
            }

            return b;
        }

        public Behavior getWalkBehavior(string behaviorName)
        {
            string query = "SELECT * FROM behavior WHERE nameBehavior = 'behaviorName' and isWalk = 1";
            query = query.Replace("behaviorName", behaviorName);

            connection = GetConnection();
            SQLiteDataReader sqlReader = null;
            Behavior b = null;
            try
            {
                connection.Open();
                SQLiteCommand sLiteCommand = new SQLiteCommand(query, connection);
                sqlReader = sLiteCommand.ExecuteReader();
                b = new Behavior(true);

                while (sqlReader.Read())
                {
                    b.Name = sqlReader.GetString(1);
                    b.ID = sqlReader.GetInt32(0);
                    b.DurationTime = sqlReader.GetInt32(5);
                    string imageData = sqlReader.GetString(2);
                    if (sqlReader.GetBoolean(3)) // is spriteSheet
                    {
                        FileStream fs = new FileStream(imageData, FileMode.Open);
                        b.Images.Add(Bitmap.FromStream(fs));
                        fs.Close();
                    }
                    else
                    {
                        string[] images = imageData.Split(new char[] { ';' });
                        for (int k = 0; k < images.Length - 1; k++)
                        {
                            FileStream fs = new FileStream(images[k], FileMode.Open);
                            b.Images.Add(Bitmap.FromStream(fs));
                            fs.Close();
                        }
                    }
                
                }

                sqlReader.Close();
                connection.Close();
            }
            catch (Exception)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_WBEHAVIOR);
            }

            return b;
        }

        public bool DeleteBehavior(Behavior behavior)
        {
            bool result = false;
            string sql = "delete from behavior where id = " + behavior.ID;

            try
            {
                Delete(sql);
                result = true;
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_BEHAVIOR_DELETE);
            }


            return result;
        }

        #endregion

        #region Triggers

        public bool SaveTrigger(Trigger newTrigger)
        {
            bool result = false;
            string sql = "insert into triggers(nameTrigger, behaviorId) values ('" + newTrigger.Name.ToUpper() + "', bid)";
            sql = sql.Replace("bid", newTrigger.MappedBehavior.ID.ToString());

            try
            {
                Save(sql);
                result = true;
            }
            catch (DuplicateNameException)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_EXISTS_TRIGGER);
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_TRIGGER_SAVE);
            }


            return result;

        }

        public bool UpdateTrigger(Trigger t)
        {
            bool result = false;
            string sql = "update triggers set nameTrigger = '" + t.Name.ToUpper() + "', behaviorId = tBehaviorId where id = " + t.ID;
            sql = sql.Replace("tBehaviorId", t.MappedBehavior.ID.ToString());

            try
            {
                Update(sql);
                result = true;
            }
            catch (DuplicateNameException)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_EXISTS_TRIGGER);
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_TRIGGER_UPDATE);
            }

            return result;
        }

        public bool DeleteTrigger(Trigger trigger)
        {
            string sql = "delete from triggers where id = " + trigger.ID + ";";
            bool result = false;

            try
            {
                Delete(sql);
                result = true;
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_TRIGGER_DELETE);
            }

            return result;
        }

        public List<Trigger> GetAllTriggers()
        {
            connection = GetConnection();
            List<Trigger> result = new List<Trigger>();
            SQLiteDataReader reader = null;
            try
            {
                string sql = "select * from triggers;";
                connection.Open();
                SQLiteCommand cmd = new SQLiteCommand(sql, connection);
                reader = cmd.ExecuteReader();

                while (reader.Read())
                {
                    Trigger t = new Trigger(reader.GetInt32(0), reader.GetString(1));
                    t.MappedBehavior = getBehavior(reader.GetInt32(2));
                    result.Add(t);
                }
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_ALL_TRIGGER);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                connection.Close();
            }

            return result;
        }

        public Trigger GetTrigger(string name)
        {
            connection = GetConnection();
            Trigger result = null;
            SQLiteDataReader reader = null;
            try
            {
                string sql = "select * from triggers where nameTrigger = '" + name.ToUpper() + "'";
                connection.Open();
                SQLiteCommand cmd = new SQLiteCommand(sql, connection);
                reader = cmd.ExecuteReader();

                if (reader.Read())
                {
                    result = new Trigger(reader.GetInt32(0), reader.GetString(1));
                    result.MappedBehavior = getBehavior(reader.GetInt32(2));
                }
            }
            catch (Exception e)
            {
                ErrorController.ShowOkError(ErrorController.LevelEditorError.DB_CONNECTION_TRIGGER);
            }
            finally
            {
                if (reader != null)
                    reader.Close();
                connection.Close();
            }

            return result;
        }

        #endregion

    }

    public class Trigger
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public Behavior MappedBehavior { get; set; }

        public Trigger(int id, string name)
        {
            ID = id;
            Name = name;
        }

        public Trigger()
        {

        }
    }

    public class Behavior
    {
        public int ID { get; set; }
        public string Name { get; set; }

        /// <summary>
        /// null if this behavior doesnt have image sequence
        /// </summary>
        private List<Image> images;
        public List<Image> Images
        {
            get { return images; }
            set { images = value; }
        }

        /// <summary>
        /// returns the first image of the images list
        /// </summary>
        public Image SpriteSheet
        {
            get { return images[0]; }
            
        }

        private List<CollisionsData> collisionMap;
        public List<CollisionsData> CollisionMap
        {
            get { return collisionMap; }
            set { collisionMap = value; }
        }


        private WaypointsCollection waypoints;
        public WaypointsCollection Waypoints
        {
            get { return waypoints; }
            set { waypoints = value; }
        }

        private bool isWalk;
        public bool IsWalk
        {
            get { return isWalk; }
            set { isWalk = value; }
        }

        private int idProjDialog;
        public int IdProjDialog
        {
            get { return idProjDialog; }
            set { idProjDialog = value; }
        }

        private int durationTime;
        public int DurationTime
        {
            get { return durationTime; }
            set { durationTime = value; }
        }

        public Behavior(int id, string name, bool isWalk)
        {
            ID = id;
            Name = name;
            images = new List<Image>();
            this.collisionMap = new List<CollisionsData>();
            waypoints = new WaypointsCollection();
            this.isWalk = isWalk;
        }

        public Behavior(bool isWalk)
        {
            images = new List<Image>();
            this.isWalk = isWalk;
            waypoints = new WaypointsCollection();
            this.collisionMap = new List<CollisionsData>();
        }

        public Behavior()
        {
            images = new List<Image>();
            waypoints = new WaypointsCollection();
            this.collisionMap = new List<CollisionsData>();
        }

        public bool IsSpriteSheet()
        {
            return images.Count == 1;
        }
    }

}
